//=============================================================================
// ProMesh.NET - .NET Web Application Framework 
//
// Copyright (c) 2003-2008 Philippe Leybaert
//
// Permission is hereby granted, free of charge, to any person obtaining a copy 
// of this software and associated documentation files (the "Software"), to deal 
// in the Software without restriction, including without limitation the rights 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is 
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in 
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//=============================================================================

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Web.Caching;
using Activa.SharpTemplate;

namespace Activa.ProMesh
{
    internal class Template
    {
        private readonly PreParsedTemplate _parsedTemplate;
        private string _pageTitle;
        private readonly string _destinationPath;
        private readonly string _fileName;

        private static readonly object _templateCacheLock = new object();
        private static readonly ProMeshTemplateRenderer _templateParser = new ProMeshTemplateRenderer();

        public static Template CreateTemplate(string templateFile, string destinationPath)
        {
            if (WebAppContext.Offline)
                return new Template(templateFile,destinationPath);

            string key = "TPL: " + destinationPath + ";" + templateFile;

            Template template = (Template) WebAppContext.WebCache[key];

            if (template != null)
                return template;

            lock (_templateCacheLock)
            {
                template = (Template) WebAppContext.WebCache[key];

                if (template != null)
                    return template;

                template = new Template(templateFile, destinationPath);

                WebAppContext.WebCache.Insert(key, template, new CacheDependency(templateFile), DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
            }

            return template;
        }

        public static Template CreateTemplate(Template callingTemplate, string templateName)
        {
            return CreateTemplate(templateName, callingTemplate._destinationPath);
        }

        private Template(string templateFile, string destinationPath)
        {
            _destinationPath = destinationPath;
            _fileName = templateFile;

            _parsedTemplate = PreParseTemplate(TemplateUtil.ReadTemplateContents(_fileName, _destinationPath));
        }

        public PreParsedTemplate PreParse()
        {
            if (WebAppContext.Offline)
                return PreParseTemplate(TemplateUtil.ReadTemplateContents(_fileName, _destinationPath));

            string key = "PREPARSE: " + _destinationPath + ";" + _fileName;

            PreParsedTemplate parsedTemplate = (PreParsedTemplate) WebAppContext.WebCache[key];

            if (parsedTemplate != null)
                return parsedTemplate;

            lock (_templateCacheLock)
            {
                parsedTemplate = (PreParsedTemplate)WebAppContext.WebCache[key];

                if (parsedTemplate != null)
                    return parsedTemplate;

                parsedTemplate = PreParseTemplate(TemplateUtil.ReadTemplateContents(_fileName, _destinationPath));

                WebAppContext.WebCache.Insert(key, parsedTemplate, new CacheDependency(_fileName), DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
            }

            return parsedTemplate;
        }

        public string PageTitle
        {
            get { return _pageTitle; }
        }

        public string Parse(ViewContext viewContext)
        {
            return _templateParser.Render(_parsedTemplate, new TemplateParserContext(viewContext,this));
        }

        public string Parse(TemplateParserContext parserContext)
        {
            return _templateParser.Render(_parsedTemplate, new TemplateParserContext(parserContext, this));
        }

        public string ParseHTMLBody(ViewContext viewContext)
        {
            return TemplateUtil.ExtractBody(Parse(viewContext));
        }

        public string ParseHTMLBody(TemplateParserContext parserContext)
        {
            return TemplateUtil.ExtractBody(Parse(parserContext));
        }

        public string GetSubTemplatePath(string templateName)
        {
            if (templateName.StartsWith("~/") || templateName.StartsWith("/"))
                return WebAppContext.Server.MapPath(templateName);
            else
                return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(_fileName), templateName));
        }

        public string ReadSubTemplate(string templateName)
        {
            string templatePath = GetSubTemplatePath(templateName);

            return TemplateUtil.ExtractBody(TemplateUtil.ReadTemplateContents(templatePath, _destinationPath));
        }

        public string RenderSubTemplate(string templateName, TemplateParserContext viewData)
        {
            string templatePath = GetSubTemplatePath(templateName);

            Template innerTemplate = CreateTemplate(this, templatePath);

            return innerTemplate.ParseHTMLBody(viewData);
        }

        private PreParsedTemplate PreParseTemplate(string unparsedText)
        {
            Match matchTitle = Regex.Match(unparsedText, @"<title\s*>(?<title>.*?)</title>");

            if (matchTitle.Success)
                _pageTitle = matchTitle.Groups["title"].Value;

            //unparsedText = Regex.Replace(unparsedText, @"(\r\n\s*)(?<tag>\<!--\$\[.*?\]--\>)(\s*\r\n)", "${tag}\r\n");

            return _templateParser.Parse(unparsedText);
        }

    }
}
